﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Xml;
using DataPurpose=Universe.OneC.DomainModel.DataPurpose;
using MetaClass=Universe.OneC.DomainModel.MetaClass;
using MetaModel=Universe.OneC.DomainModel.MetaModel;
using MetaProperty=Universe.OneC.DomainModel.MetaProperty;

namespace Universe.OneC
{
    public class MetaIO
    {
        public static XmlDocument Dump(MetaModel model)
        {
            XmlDocument ret = new XmlDocument();
            ret.AppendChild(ret.CreateElement("Model1C"));
            XmlElement root = ret.DocumentElement;

            root.AddAttribute("name", model.Name);
            root.AddAttribute("version", model.Version);

            List<string> names = new List<string>(model.Registry.Keys);
            names.Sort(
                (x, y) =>
                {
                    int v1 = model.Registry[x].GetGroup().CompareTo(model.Registry[y].GetGroup());
                    if (v1 != 0)
                        return v1;

                    return model.Registry[x].Name.CompareTo(model.Registry[y].Name);
                }
                );

            foreach (string className in names)
            {
                MetaClass metaClass = model.Registry[className];
                if (metaClass.Owner != null)
                    continue;

                XmlElement parent = root;
                DumpMetaClass(metaClass, parent, "class", true);

            }

            return ret;
        }

        private static void DumpMetaClass(MetaClass metaClass, XmlElement parent, string elementName, bool showTableParts)
        {
            XmlElement @class = parent.AddChild(elementName);

            if (showTableParts)
            {
                XmlElement fullNameElement = @class.AddChild("fullName");
                fullNameElement.InnerText = metaClass.FullName;
            }

            @class.AddAttribute("name", metaClass.Name);
            @class.AddAttribute("root", metaClass.Namespace.Root.Name);
            @class.AddAttribute("group-title", metaClass.GetGroupTitle());
            @class.AddAttribute("group", metaClass.GetGroup2().ToString());

            if (!string.IsNullOrEmpty(metaClass.Synonym))
                @class.AddAttribute("synonym", metaClass.Synonym);

            if (metaClass.BaseClass != null)
                @class.AddAttribute("base", metaClass.BaseClass.Name);

            @class.AddAttribute("kind", metaClass.Kind.ToString());

            if (metaClass.Owner != null)
                @class.AddAttribute("owner", metaClass.Owner.Name);

            if (metaClass.EnumValues != null)
            {
                foreach (var metaValue in metaClass.EnumValues)
                {
                    XmlElement value = @class.AddChild("item");
                    value.AddAttribute("value", metaValue.Value);
                    value.AddAttribute("synonym", metaValue.Name);
                }
            }

            foreach (MetaProperty metaProperty in metaClass.Properties)
            {
                XmlElement property = @class.AddChild("property");
                property.AddAttribute("name", metaProperty.Name);

                if (!string.IsNullOrEmpty(metaProperty.Synonym))
                    property.AddAttribute("synonym", metaProperty.Synonym);

                property.AddAttribute("purpose", metaProperty.Purpose.ToString());
                property.AddAttribute("nulls", metaProperty.AllowsNULL ? "allow" : "deny");
                property.AddAttribute("names", string.Join("; ", metaProperty.Names.ToArray()));
                if (metaProperty.Types != null && metaProperty.Types.Contains(typeof(DateTime)))
                {
                    property.AddAttribute("date-part", metaProperty.DatePart.ToString());
                }

                if ((metaProperty.Purpose & DataPurpose.Chameleon) != 0)
                {
                    // Debugger.Break();
                }
            }

            if (showTableParts)
            {
                DumpTableParts(@class, metaClass);
            }
            else
            {
            }
        }

        private static void DumpTableParts(XmlElement parent, MetaClass owner)
        {
            foreach (var @class in owner.Model.Registry.Values)
            {
                if (@class.Owner == owner)
                {
                    DumpMetaClass(@class, parent, "Part", false);
                }
            }
        }


    }

    public static class MyXmlExtensions
    {
        public static XmlElement AddChild(this XmlElement parent, string name)
        {
            XmlElement ret = parent.OwnerDocument.CreateElement(name);
            parent.AppendChild(ret);
            return ret;
        }

        public static XmlElement AddAttribute(this XmlElement parent, string name, string value)
        {
            parent.SetAttribute(name, value);
            return parent;
        }
    }

}
